package com.niiwoo.civet.account.service.local;

import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.AccountBaseExample;
import com.niiwoo.civet.account.dao.mapper.AccountBaseMapperExt;
import com.niiwoo.civet.base.constant.OrgConstant;
import com.niiwoo.tripod.lanmao.enums.UserAuthorizationEnum;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 账户本地service
 * Created by wangjichao on 2017/11/11.
 */
@Service
public class AccountService {
    private static final Logger logger = LoggerFactory.getLogger(AccountService.class);

    @Autowired
    private AccountBaseMapperExt accountBaseMapperExt;


    /**
     * 获取账户信息：根据账户主键id
     * 不存在则抛出异常
     *
     * @param accountId
     * @return
     */
    public AccountBase loadAccountById(Long accountId) {
        Assert.notNull(accountId,"accountId不能为空");
        if(accountId == -1){
            return null;//存管上线时迁移旧数据时accountId=-1
        }

        AccountBase accountBase = accountBaseMapperExt.selectByPrimaryKey(accountId);
        if(Objects.isNull(accountBase)){
            throw new BizException("ACC10001");// 存管账户未开通
        }

        return accountBase;
    }

    public List<AccountBase> loadAccountsByIds(Collection<Long> accountIds) {
        List<Long> accountIdList = accountIds.stream().filter(accountId -> null != accountId)
                                                      .filter(accountId -> accountId != -1)
                                                      .collect(Collectors.toSet()).stream().collect(Collectors.toList());

        if(!CollectionUtils.isEmpty(accountIdList)){
            AccountBaseExample example = new AccountBaseExample();
            AccountBaseExample.Criteria criteria = example.createCriteria();
            criteria.andIdIn(accountIdList);
            return accountBaseMapperExt.selectByExample(example);
        }

        return Collections.EMPTY_LIST;
    }

    /**
     * 从主库查询
     * @param accountId
     * @return
     */
    @Transactional
    public AccountBase loadAccountByIdFromMaster(Long accountId){
        return this.loadAccountById(accountId);
    }

    /**
     * 获取账户信息并锁定：根据账户主键id
     * 不存在则抛出异常
     * @param accountId
     * @return
     */
    public AccountBase loadAccountByIdForUpdate(Long accountId) {
        Assert.notNull(accountId,"accountId不能为空");

        AccountBase accountBase = accountBaseMapperExt.selectByPrimaryKeyForUpdate(accountId);
        if(Objects.isNull(accountBase)){
            throw new BizException("ACC10001");// 存管账户未开通
        }

        return accountBase;
    }

    /**
     * 获取账户信息并锁定：根据存管账户号
     * 不存在则抛出异常
     * @param accountNo
     * @return
     */
    public AccountBase loadAccountByAccountNo(String accountNo) {
        Assert.hasLength(accountNo,"accountNo不能为空");

        AccountBaseExample example = new AccountBaseExample();
        AccountBaseExample.Criteria criteria = example.createCriteria();
        criteria.andAccountNoEqualTo(accountNo);

        List<AccountBase> accountBaseList = accountBaseMapperExt.selectByExample(example);
        if(CollectionUtils.isEmpty(accountBaseList)){
            throw new BizException("ACC10001");// 存管账户未开通
        }
        return accountBaseList.get(0);
    }


    /**
     * 查询账户信息：根据账户主键id + 账户角色 + 机构id
     * 不存在则返回null
     * @param userId
     * @param role
     * @param orgId
     * @return
     */
    public AccountBase getAccount(String userId, UserRoleEnum role, String orgId){
        Assert.hasLength(userId,"userId不能为空");
        Assert.notNull(role,"role不能为空");
        Assert.hasLength(orgId,"orgId不能为空");

        AccountBaseExample example = new AccountBaseExample();
        AccountBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andAccountRoleEqualTo(role.getValue());
        criteria.andOrgIdEqualTo(orgId);

        List<AccountBase> accountBaseList = accountBaseMapperExt.selectByExample(example);
        if(CollectionUtils.isEmpty(accountBaseList)){
            return null;
        }
        return accountBaseList.get(0);
    }


    /**
     * 查询平台用户账户信息：根据账户主键id + 账户角色
     * 不存在则返回null
     * @param userId
     * @param role
     * @return
     */
    public AccountBase getNiiwooAccount(String userId, UserRoleEnum role) {
        return this.getAccount(userId, role, OrgConstant.NIIWOO_ORG_ID);
    }

    /**
     * 获取平台用户账户信息：根据用户id + 账户角色
     * 不存在则抛出异常
     * @param userId
     * @param role
     * @return
     */
    public AccountBase loadNiiwooAccount(String userId, UserRoleEnum role) {
        AccountBase accountBase = this.getNiiwooAccount(userId, role);
        if(Objects.isNull(accountBase)){
            throw new BizException("ACC10001");// 存管账户未开通
        }

        return accountBase;
    }

    /**
     * 查询平台用户账户信息列表：根据用户id
     * @param userId
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<AccountBase> listNiiwooAccountByUserId(String userId) {
        Assert.hasLength(userId,"userId不能为空");

        AccountBaseExample example = new AccountBaseExample();
        AccountBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andOrgIdEqualTo(OrgConstant.NIIWOO_ORG_ID);
        return accountBaseMapperExt.selectByExample(example);
    }

    /**
     * 查询平台用户账户信息列表：根据用户id
     * @param userId
     * @return
     */
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public List<AccountBase> listNiiwooAccountByUserId(String userId,String orgId) {
        Assert.hasLength(userId,"userId不能为空");
        Assert.hasLength(userId,"orgId不能为空");

        AccountBaseExample example = new AccountBaseExample();
        example.setOrderByClause("update_time desc");
        AccountBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andOrgIdEqualTo(orgId);
        return accountBaseMapperExt.selectByExample(example);
    }

    /**
     * 查询用户拥有的全部账户
     * @param userId
     * @return
     */
    public List<AccountBase> listAccountByUserId(String userId) {
        Assert.hasLength(userId,"userId不能为空");

        AccountBaseExample example = new AccountBaseExample();
        AccountBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        return accountBaseMapperExt.selectByExample(example);
    }

    /**
     * 查询机构用户账户信息：根据用户id + 机构id
     * 不存在则返回null
     * @param userId
     * @param orgId
     * @return
     */
    public AccountBase getOrgAccount(String userId, String orgId) {
        Assert.hasLength(userId,"userId不能为空");
        Assert.hasLength(orgId,"orgId不能为空");

        AccountBaseExample example = new AccountBaseExample();
        AccountBaseExample.Criteria criteria = example.createCriteria();
        criteria.andUserIdEqualTo(userId);
        criteria.andOrgIdEqualTo(orgId);

        List<AccountBase> accountBaseList = accountBaseMapperExt.selectByExample(example);
        if(CollectionUtils.isEmpty(accountBaseList)){
            return null;
        }
        return accountBaseList.get(0);
    }

    /**
     * 获取机构用户账户信息：根据用户id + 机构id
     * 不存在则抛出异常
     * @param userId
     * @param orgId
     * @return
     */
    public AccountBase loadOrgAccount(String userId, String orgId) {
        AccountBase accountBase = this.getOrgAccount(userId, orgId);
        if(Objects.isNull(accountBase)){
            throw new BizException("ACC10001");// 存管账户未开通
        }
        return accountBase;
    }



    @Transactional
    public void enableUserAuthrozition(String accountNo, Set<UserAuthorizationEnum> authorizations) {
        AccountBase existAccount = this.loadAccountByAccountNo(accountNo);

        AccountBase account = new AccountBase();
        account.setId(existAccount.getId());
        for (UserAuthorizationEnum authorization : authorizations) {
            switch (authorization) {
                case TENDER:
                    account.setTender((byte) 1);
                    break;
                case REPAYMENT:
                    account.setRepayment((byte) 1);
                    break;
                case CREDIT_ASSIGNMENT:
                    account.setCreditAssignment((byte) 1);
                    break;
                case COMPENSATORY:
                    account.setCompensatory((byte) 1);
                    break;
                case WITHDRAW:
                    account.setWithdraw((byte) 1);
                    break;
                case RECHARGE:
                    account.setRecharge((byte) 1);
                    break;
                default:
                    logger.warn("no authorization property defined in AccountBase for:{}", authorization);
                    break;
            }
        }
        accountBaseMapperExt.updateByPrimaryKeySelective(account);
    }

    @Transactional
    public void disableUserAuthorization(Long accountId, List<UserAuthorizationEnum> authorizations) {
        AccountBase record = new AccountBase();
        record.setId(accountId);
        for (UserAuthorizationEnum authorization : authorizations) {
            switch (authorization) {
                case TENDER:
                    record.setTender((byte) 0);
                    break;
                case REPAYMENT:
                    record.setRepayment((byte) 0);
                    break;
                case CREDIT_ASSIGNMENT:
                    record.setCreditAssignment((byte) 0);
                    break;
                case COMPENSATORY:
                    record.setCompensatory((byte) 0);
                    break;
                case WITHDRAW:
                    record.setWithdraw((byte) 0);
                    break;
                case RECHARGE:
                    record.setRecharge((byte) 0);
                    break;
                default:
                    break;
            }
        }
        accountBaseMapperExt.updateByPrimaryKeySelective(record);
    }


}
